﻿#ifndef EXPRVALUE_H
#define EXPRVALUE_H

#include <QBitArray>
#include <iostream>
#include <QList>
#include <list>
#include <functional>

extern void AbortException(QString& errmsg);


//合法的大于0，非法小于0

//对象的转换关系类型
enum exprTypeTranStatus{
    EXPR_to_Err = -100,
    EXPR_Int_to_String, //整数转字符串，非法，下同
    EXPR_Int64_to_String,
    EXPR_Float_to_String,
    EXPR_String_to_Int,
    EXPR_String_to_Int64,
    EXPR_String_to_Float,

    //下面是合法的，不过有些会精度丢失
    EXPR_Int_to_Int = 0,
    EXPR_Int_to_Int64,
    EXPR_Int_to_Float,

    EXPR_Int64_to_Int64,
    EXPR_Int64_to_Int,
    EXPR_Int64_to_Float,
    EXPR_Int_to_Char,
    EXPR_Int_to_WChar,

    EXPR_Float_to_Float,
    EXPR_Float_to_Int,
    EXPR_Float_to_Int64,

    EXPR_String_to_String,
    EXPR_String_to_U16String,
    EXPR_String_to_File,

    EXPR_U16String_to_U16String,
    EXPR_U16String_to_String,
    EXPR_Bool_to_Bool,

    EXPR_Char_to_Char,
    EXPR_Char_to_String,
    EXPR_Char_to_Int,
    EXPR_Char_to_Int64,
    EXPR_WChar_to_Int64,
    EXPR_Char_to_WChar,
    EXPR_Char_to_U16String,

    EXPR_WChar_to_Int,

    EXPR_WChar_to_WChar,
    EXPR_WChar_to_U16String,

    EXPR_Struct_to_Struct,
    EXPR_StructDesc_to_StructDesc,
    EXPR_List_to_List,
    EXPR_Map_to_Map,
    EXPR_File_to_File,
    EXPR_Date_to_Date,
    EXPR_Fun_to_Fun,
    EXPR_Excel_to_Excel,

    //EXPR_string_to_Pstring,
    //EXPR_U16String_to_U16String,

    EXPR_string_to_Struct,
    EXPR_MemFun_to_Fun, //暂时没用


};


enum ExprValueType {
    EXPR_INT_OPTION = -100, // 可选的INT 参数，本身不使用，在cpp参数检查中使用，可以有一个可选的Int参数。
    EXPR_PARA_DYNANIC,//支持动态参数，主要用在函数的重载中。即先不约束具体的类型，后续智能批量。
    EXPR_ERR = -1,//类型错误
    EXPR_INT = 0,
    EXPR_INT64,
    EXPR_FLOAT,
    EXPR_BOOL,
    EXPR_CHAR,
    EXPR_WCHAR,//对应QChar
    EXPR_BASIC_VAR,//基本变量，本身不用，表明之前的都是基本变量，没有额外的内存指针
    EXPR_STRUCT_DEC,//结构体声明,不是结构体，而且声明类型
    EXPR_STRUCT,//结构体变量本身
    EXPR_STRING,
    EXPR_U16STRING,//对应QString，是UTF16大端序列
    EXPR_LIST,
    EXPR_MAP,
    EXPR_FILE,
    EXPR_DATE,
    EXPR_EXCEL,//表格
    EXPR_FUN,//普通函数
    EXPR_CALL_BACK_FUN,//回调函数
    EXPR_MEMFUN,//成员函数
    EXPR_GLOBAL_PACKNAME,//全局包名方法，比如ndd pin 等。如果是全局包名，则value.vpacktype执行具体的包名iD
    EXPR_MULTI_FUN_CALL_CTX,//多级调用中，原始的ctx
    EXPR_PIN,//pin 系统 内部的方法，做全局包名使用
    EXPR_NDD,//ndd的包名方法。

    //EXPR_ALL_PACK_FUN,//目前就是desc，所有包名都有的方法。
    EXPR_MAX_END,
};
enum Type_Compare_Staus {
    CAN_NOT_CMP = -100,
    LESS_STATUS = -1, //小于
    EQUAL_STATUS = 0, //等于
    GREATER_STATUS = 1,//大于
    UNEQUAL_STATUS,//不等
};


class ExprValue //感觉可以合并SymNode
{
public:
    ExprValue();
    ExprValue(std::string str);
    std::string getString(); //如果是字符串，则获取字符串的类型
    void setString(std::string str,bool needFree=false);
    void setStringBytes(QByteArray& bytes);

    std::string& getStructName();//如果是结构体，则获取结构体的类型
    int getStructTypeId();//如果是结构体，则获取结构体的类型对应的ID，和getStructName一样，加快对比

    std::string getFilePath();

    std::string* varName;

    const std::string getPackName() const ;//获取全局包名，即vtype
    int type;
    union {
        bool vbool;
        char vchar;
        unsigned char vuschar;
        unsigned short vwchar;
        int vint;
        qint64 vint64;
        double vfloat;
        //double vdouble;
        //char* vtype; //全局的包名
        int vpacktype;//包类型，使用EXPR_TYPE类型。
        void* vpoint;
    }value;

    void print(std::string name);
    bool freeList();
    void doClearList();

    bool freeMap();
    void doClearMap();

    bool freeFile();
    bool freeExcel();
    QString toString();
    ExprValue deepCopy(bool isLbMapDeepCopy = false) const;
    ExprValue* deepCopy2(bool isLbMapDeepCopy=false);
    ExprValue* shallowMoveCopy();
    //void deepCopyStructMemType();
    bool operator==(const ExprValue& other) const;
    void freeMem();
    //void setTypeName(std::string& typeName);
    QString* getU16String();
    QChar getQChar();

    bool isMapKeyType();


    //static QMap<std::string, char*> s_packName_map;

};

int exprTypeMatch(int nameType, int valueType, bool iswarn = false, bool autoTransType = false, ExprValue* expr=nullptr);

//对于函数调用中，凡是传递引用的对象，而且是列表、文件、字典三类，如果计数已经为0，则走真实删除。
//只在函数cpp底层调用后销毁引用对象的时候使用。
void freeRefObjMem(ExprValue* expr);

//bool ExprValue::operator==(const ExprValue_& other) 要同步更新，一旦这里修改后。
namespace std {
template<>
struct hash<ExprValue> {
    std::size_t operator()(const ExprValue& p) const {
        // 计算哈希值的简单方法：组合姓名和年龄的哈希值
        //如果是整数
        switch (p.type)
        {
        case EXPR_INT:
            {
            return std::hash<long long int>()(p.value.vint);
        }
            break;
        case EXPR_INT64:
        {
            return std::hash<long long int>()(p.value.vint64);
        }
            break;
        case EXPR_CHAR:
        {
            return std::hash<int>()(p.value.vuschar);
        }
        break;
        case EXPR_WCHAR:
        {
            return std::hash<int>()(p.value.vwchar);
        }
        break;
        case EXPR_STRING:
        {
            if (p.value.vpoint != nullptr)
            {
            QByteArray *pb = (QByteArray*)p.value.vpoint;
            return std::hash<std::string>()(pb->toStdString());
        }

        }
        break;

        case EXPR_U16STRING:
        {
            if (p.value.vpoint != nullptr)
            {
                QString* pb = (QString*)p.value.vpoint;
                return std::hash<std::wstring>()(pb->toStdWString());
            }

        }
            break;
        }

        QString msg = QString(u8"错误：只有整数、字符、字符串能做字典的关键字,当前表达式类型不可做关键字！");
        AbortException(msg);
        return 0;
    }
};
}

int CompareExprAndExpr(ExprValue& pSym, ExprValue& expr, bool iswarn = true);

#endif // EXPRVALUE_H
